package raw

import (
	"github.com/pkg/errors"
	"yizhuoyan/go-study/pdfgo/handyio"
	"yizhuoyan/go-study/pdfgo/raw/contents"
	"yizhuoyan/go-study/pdfgo/raw/elements"
	"yizhuoyan/go-study/pdfgo/raw/objects/basicobject"
	"yizhuoyan/go-study/pdfgo/raw/objects/indirectobject"
)

type PdfFileModel struct {
	header              *elements.HeaderElement
	body                *elements.BodyElement
	crossReferenceTable *elements.CrossReferenceTableElement
	trailer             *elements.TrailerElement
	UpdatedList         []*elements.IncrementalUpdateElement
	reader              handyio.PdfRawReader
}

func (this *PdfFileModel) Parse(reader handyio.PdfRawReader) error {
	this.reader = reader
	err := reader.IndexMoveTo(0)
	if err != nil {
		return err
	}
	this.header = new(elements.HeaderElement)
	if err = this.header.Read(reader); err != nil {
		return err
	}
	var startXref = new(elements.StartXrefElement)
	if err = startXref.Read(reader); err != nil {
		return err
	}
	xrefStartIndex := startXref.XrefStartIndex
	this.crossReferenceTable = new(elements.CrossReferenceTableElement)
	this.trailer = new(elements.TrailerElement)
	var currentTrailer = this.trailer
	var currentXrefTable = this.crossReferenceTable
	for xrefStartIndex > 0 {
		if err = reader.IndexMoveTo(xrefStartIndex); err != nil {
			return err
		}
		if err = currentXrefTable.Read(reader); err != nil {
			return err
		}
		if err = currentTrailer.Read(reader); err != nil {
			return err
		}
		if currentTrailer.FieldPrev() != nil {
			xrefStartIndex = currentTrailer.FieldPrev().ValueInt64()
			if xrefStartIndex > 0 {
				currentXrefTable.Previous = new(elements.CrossReferenceTableElement)
				currentTrailer.Previous = new(elements.TrailerElement)
				currentXrefTable = currentXrefTable.Previous
				currentTrailer = currentTrailer.Previous
			}
		} else {
			break
		}
	}
	//root document-catalog
	rootCatalogContentRef := this.trailer.RequiredFieldRoot()
	this.body = &elements.BodyElement{
		RootDocumentCatalogRef: rootCatalogContentRef,
		Locator:                this,
	}
	return nil
}
func (this *PdfFileModel) LoadIndirectObject(ref *basicobject.IndirectObjectReference) (*indirectobject.IndirectObject, error) {
	//load
	objIndex, objGn := this.crossReferenceTable.GetObjIndexAndGn(ref.ObjectNumber)
	if objIndex <= 0 {
		return nil, nil
	}
	err := this.reader.IndexMoveTo(objIndex)
	if err != nil {
		return nil, errors.Wrapf(err, "移动到对象%v %v下标", objIndex, objGn)
	}
	var rst = new(indirectobject.IndirectObject)
	if err = rst.UnSerialize(this.reader); err != nil {
		return nil, errors.Wrapf(err, "解析对象%v %v", ref.ObjectNumber, objGn)
	}
	return rst, nil
}
func (this *PdfFileModel) GetRootDocumentCatalog() (*contents.DocumentCatalog, error) {
	catalog, err := this.body.GetDocumentCatalog()
	if err != nil {
		return nil, err
	}
	return catalog, nil
}
func (this *PdfFileModel) GetPage(page int) (*contents.Page, error) {
	pages, err := this.GetPages()
	if err != nil {
		return nil, err
	}
	return pages[page], nil
}
func (this *PdfFileModel) GetPages() ([]*contents.Page, error) {
	pages, err := this.body.GetPages()
	if err != nil {
		return nil, err
	}
	return pages, nil
}
